'use strict';
const assert = require('assert');
const Service = require('egg').Service;

class ClientService extends Service {
  get _clientModel() {
    return this.app.model.Client;
  }
  get _userModel() {
    return this.app.model.User;
  }


  async getUrlByClientId(clientId) {
    const client = await this._clientModel.findOne({ where: { clientId } });
    return client.url;
  }
  /**
   * 创建应用
   * @param {String} name 应用名称
   * @param {String} clientId 应用id
   * @param {String} clientSecret 密钥
   * @param {String} grants 授权方式
   * @param {String} url 访问地址
   * @param {String} redirectUri 回调地址
   * @param {String} publicKey 公钥
   * @param {String} privateKey 私钥
   * @param {String} lid  管理员号
   * @param {String} userEmail 管理员email
   * @return {Promise<{result: Number, msg: String}>} 返回结果
   */
  async create(name, clientId, clientSecret, grants, url, redirectUri, publicKey, privateKey, lid, userEmail) {
    if (!clientSecret) {
      clientSecret = this.ctx.helper.randomString(12);
    }
    let exist = await this._clientModel.findOne({
      where: {
        name,
      },
    });
    assert(!exist, '项目名已存在');
    if (clientId) {
      exist = await this._clientModel.findOne({
        where: {
          clientId,
        },
      });
      assert(!exist, 'clientId已存在');
    } else {
      clientId = this.ctx.helper.randomString(12);
      while (await this._clientModel.findOne({ where: { clientId } })) {
        clientId = this.ctx.helper.randomString(12);
      }
    }
    if (publicKey && privateKey) {
      const ifMatch = this.service.crypto.ifMatch(publicKey, privateKey);
      assert(ifMatch, '公密钥不匹配');
    } else {
      const newKeys = this.service.crypto.generateKeys();
      publicKey = newKeys.publicKey;
      privateKey = newKeys.privateKey;
    }
    publicKey = encodeURIComponent(publicKey);
    privateKey = encodeURIComponent(privateKey);
    await this._clientModel.create({
      name, clientId, clientSecret, grants, url, redirectUri, publicKey, privateKey, lid, userEmail,
    });
    return {
      result: 0,
    };
  }

  /**
   * 删除应用
   * @param {String} id 应用id
   * @return {Promise<{result: Number, msg: String}>} 返回结果
   */
  async delete(id) {
    const data = await this._clientModel.findOne({
      where: {
        id,
      },
    });
    assert(data, '应用不存在');
    await this._clientModel.destroy({
      where: {
        id,
      },
    });
    return {
      result: 0,
    };
  }

  /**
   * 修改应用
   * @param {Number} id id
   * @param {String} name 应用名称
   * @param {String} clientId 应用id
   * @param {String} clientSecret 密钥
   * @param {String} grants 授权方式
   * @param {String} url 访问地址
   * @param {String} redirectUri 回调地址
   * @param {String} publicKey 回调地址
   * @param {String} privateKey 回调地址
   * @param {String} lid 用户号
   * @param {String} userEmail 用户邮箱
   * @return {Promise<{result: Number, msg: String}>} 返回结果
   */
  async update(id, name, clientId, clientSecret, grants, url, redirectUri, publicKey, privateKey, lid, userEmail) {
    const value = { name, clientSecret, grants, url, redirectUri, lid, userEmail };
    if (privateKey && publicKey) {
      const ifMatch = this.service.crypto.ifMatch(publicKey, privateKey);
      assert(ifMatch, '公密钥不匹配');

      publicKey = encodeURIComponent(publicKey);
      privateKey = encodeURIComponent(privateKey);
      Object.assign(value, { publicKey, privateKey });
    }
    const res = await this._clientModel.update(value, {
      where: {
        id,
        clientId,
      },
    });
    assert(res[0], '未找到该应用');
    return {
      result: 0,
    };
  }

  /**
   * 分页获取应用
   * @param {Number} page 页码
   * @param {Number} size 每页数量
   * @param {String} content 查询内容
   * @return {Promise<{result: Number, msg: String}>} 返回结果
   */
  async getPage(page, size, content) {
    let where;
    const Op = this.app.Sequelize.Op;
    if (content) {
      where = {
        [Op.or]: {
          clientId: {
            [Op.like]: `%${content}%`,
          },
          name: {
            [Op.like]: `%${content}%`,
          },
        },
      };
    }
    const res = await this._clientModel.findAndCountAll({
      where,
      limit : size,
      offset: (page - 1) * size,
    });
    res.rows = res.rows.map(obj => {
      obj.publicKey = decodeURIComponent(obj.publicKey);
      obj.privateKey = decodeURIComponent(obj.privateKey);
      return obj;
    });
    return res;
  }
}
module.exports = ClientService;
